﻿using System;
using System.Collections.Generic;
using AdaptationProject.Utils;
using SharedTypes;
using System.IO;
using GeneticAlgorithm;

namespace AdaptationProject
{
    /// <summary>
    /// Объект выполнения процесса адаптации. Используется для
    /// выполнения процесса адаптации в фоновом потоке.
    /// </summary>
    public class AnalisysWithStateObject
    {
        /// <summary>
        /// Метод адаптации параметров.
        /// </summary>
        private IAdoptationMethod adoMethod;

        /// <summary>
        /// Алгоритм исполнительного файла данных.
        /// </summary>
        private IAlgorithm currentCompression;

        /// <summary>
        /// Контейнер отчётной информации.
        /// </summary>
        public ReportInformationContainer repoInfo;

        /// <summary>
        /// Контейнер отчётной информации о каждом файле.
        /// </summary>
        public IList<ReportInformationContainer> listReportFile;

        /// <summary>
        /// События завершения процесса адаптации.
        /// </summary>
        public EventHandler<AdoptationDonEventArgs> OnProcessDone;

        /// <summary>
        /// Устанавливает количество экспериментов в 
        /// структуре RaportInformationContainer
        /// </summary>
        public void SetNumberofExperiments(double numExperiments)
        {
            repoInfo.ExperimentCount = numExperiments;
        }

        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="adopt">Метод адаптации.</param>
        /// <param name="algo">Алгоритм исполнительного файла.</param>
        /// <param name="repInfo">Ссылка на контейнер отчётной информации.</param>
        public AnalisysWithStateObject(IAdoptationMethod adopt, IAlgorithm algo, ref ReportInformationContainer repInfo)
        {
            adoMethod = adopt;
            currentCompression = algo;
            repoInfo = repInfo;
            listReportFile = new List<ReportInformationContainer>();
        }

        void GenerateReport(IList<StreamWriter> listWriter, ref int iCount)
        {
            string strInterface = "№ експ\tТипФайла\tКол.експерементов\tМах поколение\tКоличество особей в популяции\tВремя поиска\tРазмер с рек.\tПараметрами\tРазмер с рацион.\tПарам";

            repoInfo.SupCompression = new List<double>();
            repoInfo.RegCompression = new List<double>();
            repoInfo.SupTime = new List<double>();
            repoInfo.RegTime = new List<double>();
            repoInfo.SearchingTime = TimeSpan.Zero;
            listReportFile.Clear();

            for (int i = 0; i < this.repoInfo.ExperimentCount; i++)
            {
                adoMethod.Adopt(currentCompression, ref repoInfo);
            }
            //OnProcessDone.Invoke(this, new AdoptationDonEventArgs(repoInfo.FindedParameters));

            // Прогнать каждый файл через рекомендуемые и рациональные параметры
            // РАсчитать SUP, REG
            FileInfo[] copyFileInfo = repoInfo.FileNames;
            for (int num = 0; num < copyFileInfo.Length; ++num)
            {
                ReportInformationContainer reportCurrentFile = new ReportInformationContainer();
                reportCurrentFile.CopyHere(repoInfo, true);

                reportCurrentFile.FileNames = new FileInfo[1];
                reportCurrentFile.FileNames[0] = copyFileInfo[num];
                for (int i = 0; i < this.repoInfo.ExperimentCount; i++)
                {
                    adoMethod.CompressFileByParams(currentCompression, repoInfo, ref reportCurrentFile);
                }
                listReportFile.Add(reportCurrentFile);
            }


            List<object> geneticParams;
            adoMethod.GetParameters(out geneticParams);
            for (int j = 0; j < listReportFile.Count; ++j)
            {
                if (j + 1 > listWriter.Count)
                {
                    StreamWriter tmp = File.CreateText("Report_" + DateTime.Now.ToString().Replace(':', '.').Replace('/', '.') + "_" + j + ".txt");
                    listWriter.Add(tmp);
                    tmp.WriteLine(strInterface);
                }
                string str = iCount + "\t" + listReportFile[j].FileNames[0].Extension + "\t" + repoInfo.ExperimentCount + "\t" +
                    GeneticAlgorithmSettings.MaxGeneration + "\t" +
                    GeneticAlgorithmSettings.PopulationAmount + "\t" +
                    repoInfo.SearchingTimeFomatted + "\t" +
                    listReportFile[j].CalculateDirSize() + "\t" +
                    listReportFile[j].recommendedResult + "\t" +
                    Math.Round(listReportFile[j].bestSize);
                listWriter[j].WriteLine(str);

            }
            ++iCount;
        }
        /// <summary>
        /// Запускает процесс адаптации параметров алгоритма.
        /// </summary>
        public void RunResearchReport()
        {
            StreamWriter writer = File.CreateText("Report_" + DateTime.Now.ToString().Replace(':', '.').Replace('/', '.') + ".txt");
            IList<StreamWriter> listWriter = new List<StreamWriter>();
            listWriter.Add(writer);
            {
                string strInterface = "№ експ\tТипФайла\tКол.експерементов\tМах поколение\tКоличество особей в популяции\tВремя поиска\tРазмер с рек.\tПараметрами\tРазмер с рацион.\tПарам";
                writer.WriteLine(strInterface);
                int iCount = 0;

                for (GeneticAlgorithmSettings.PopulationAmount = 5; GeneticAlgorithmSettings.PopulationAmount < 15; ++GeneticAlgorithmSettings.PopulationAmount)
                {
                    GenerateReport(listWriter, ref iCount);
                }
                GeneticAlgorithmSettings.PopulationAmount = 5;
                for (GeneticAlgorithmSettings.MaxGeneration = 5; GeneticAlgorithmSettings.MaxGeneration < 15; ++GeneticAlgorithmSettings.MaxGeneration)
                {
                    GenerateReport(listWriter, ref iCount);
                }
            }
            for (int i = 0; i < listWriter.Count; ++i )
            {
                listWriter[i].Close();
            }
        }

        /// <summary>
        /// Запускает процесс адаптации параметров алгоритма.
        /// </summary>
        public void RunAdoptation()
        {
            repoInfo.SupCompression = new List<double>();
            repoInfo.RegCompression = new List<double>();
            repoInfo.SupTime = new List<double>();
            repoInfo.RegTime = new List<double>();
            for (int i = 0; i < this.repoInfo.ExperimentCount; i++)
            {
                adoMethod.Adopt(currentCompression, ref repoInfo);
            }
            OnProcessDone.Invoke(this, new AdoptationDonEventArgs(repoInfo.FindedParameters));

            // Прогнать каждый файл через рекомендуемые и рациональные параметры
            // РАсчитать SUP, REG
            FileInfo[] copyFileInfo = repoInfo.FileNames;
            for (int num = 0; num < copyFileInfo.Length; ++num)
            {
                ReportInformationContainer reportCurrentFile = new ReportInformationContainer();
                reportCurrentFile.CopyHere(repoInfo, true);

                reportCurrentFile.FileNames = new FileInfo[1];
                reportCurrentFile.FileNames[0] = copyFileInfo[num];
                for (int i = 0; i < this.repoInfo.ExperimentCount; i++)
                {
                    adoMethod.CompressFileByParams(currentCompression, repoInfo, ref reportCurrentFile);
                }
                listReportFile.Add(reportCurrentFile);
            }

            ReportGenerator.GenerateReport(repoInfo, listReportFile, adoMethod, currentCompression.ExeName);
            ReporterSize.Report(listReportFile);
        }

        /// <summary>
        /// Запускает процесс адаптации параметров алгоритма для каждого файла.
        /// </summary>
        public void RunDevFileAdoptation()
        {
            repoInfo.SupCompression = new List<double>();
            repoInfo.RegCompression = new List<double>();
            repoInfo.SupTime = new List<double>();
            repoInfo.RegTime = new List<double>();

            FileInfo[] copyFileInfo = repoInfo.FileNames;
            for (int num = 0; num < copyFileInfo.Length; ++num)
            {
                ReportInformationContainer reportCurrentFile = repoInfo;

                reportCurrentFile.FileNames = new FileInfo[1];
                reportCurrentFile.FileNames[0] = copyFileInfo[num];
                for (int i = 0; i < this.repoInfo.ExperimentCount; i++)
                {
                    adoMethod.Adopt(currentCompression, ref reportCurrentFile);
                }
                listReportFile.Add(reportCurrentFile);
                //ReportGenerator.GenerateReport(reportCurrentFile);
            }

            // Генерировать общий репорт
            //ReportGenerator.GenerateReport(listReportFile);

            OnProcessDone.Invoke(this, new AdoptationDonEventArgs(repoInfo.FindedParameters));
        }
    }

    /// <summary>
    /// Класс параметров события завершения адаптации.
    /// </summary>
    public class AdoptationDonEventArgs : EventArgs
    {
        /// <summary>
        /// Список лучших параметров, найденных в процессе адаптации.
        /// </summary>
        public readonly IDictionary<int, LinkedParameter> bestParameters;

        /// <summary>
        /// Конструктор.
        /// </summary>
        /// <param name="parameters">Список найденных параметров.</param>
        public AdoptationDonEventArgs(IDictionary<int, LinkedParameter> parameters)
        {
            bestParameters = parameters;
        }
    }
}
